package main

import (
	"baliance.com/gooxml/document"
	"bufio"
	"bytes"
	"encoding/csv"
	"fmt"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	showLock := 0
	csvPath := ""
	savePath := ""
	placeNum := 0
	csvData := make([][]string, 0)
	for true {
		if showLock == 0 {
			fmt.Print("请输入创建替换word内容的csv表格的文件夹目录（输入'exit'退出）：")
			csvPath, _ = reader.ReadString('\n')
			csvPath = strings.TrimSpace(csvPath)
			if csvPath == "exit" {
				break
			}
			fmt.Println("")

			fmt.Print("请输导出word的文件夹目录（输入'exit'退出）：")
			savePath, _ = reader.ReadString('\n')
			savePath = strings.TrimSpace(savePath)
			if savePath == "exit" {
				break
			}
			fmt.Println("")

			fmt.Print("请输使用的占位符总数（输入'exit'退出）：")
			placeNumStr, _ := reader.ReadString('\n')
			placeNumStr = strings.TrimSpace(placeNumStr)
			if placeNumStr == "exit" {
				break
			}
			if placeNumStr != "" {
				var tmp float64
				_, err := fmt.Sscanf(placeNumStr, "%f", &tmp)
				if err != nil {
					fmt.Println("输入的使用的占位符总数转换错误")
					continue
				}
				i, _ := strconv.Atoi(fmt.Sprintf("%1.0f", tmp))
				placeNum = i
			}
			if placeNum < 3 {
				fmt.Println("输入的占位符数量需要大于2")
				continue
			}
			fmt.Println("")
		}
		showLock = 1
		fmt.Print("请输入需要的操作：1-创建替换内容的csv，2-读取csv内容，3-导出word（输入'exit'退出）：")
		doType, _ := reader.ReadString('\n')
		doType = strings.TrimSpace(doType)
		if doType == "exit" {
			break
		}
		fmt.Println("")

		//执行操作
		switch doType {
		case "1":
			//创建替换word内容的csv表格
			err := createWordCsvFile(csvPath, []string{})
			if err != nil {
				fmt.Println("创建word替换了内容csv表格错误", err.Error())
			}
		case "2":
			//读取替换word内容的csv表格
			var err error
			csvData, err = readWordCsvFile(csvPath)
			if err != nil {
				fmt.Println("读取替换word内容的csv表格错误", err.Error())
			}
			//补全长度
			if len(csvData) > 0 {
				for key, value := range csvData {
					if len(value) < 4 {
						for i := 0; i < 4-len(value); i++ {
							csvData[key] = append(csvData[key], "")
						}
					}
				}
			}
			fmt.Println("读取csv成功！！！,请执行导出操作")
		case "3":
			if len(csvData) == 0 {
				fmt.Println("还未读取csv数据，请读取csv数据之后再进行操作！")
			}
			//替换word内容导出
			templateFile := filepath.Join(csvPath, "template.docx")
			if len(csvData) > 0 {
				for _, value := range csvData {
					replaceWordText(templateFile, savePath, value, placeNum)
				}
			}
		}
	}

}

/**
 * @Description:将文件名生成为csv
 * @param csvPath
 * @param fileName
 * @author liyuan
 */
func createWordCsvFile(csvPath string, fileName []string) error {
	if csvPath == "" {
		return fmt.Errorf("表格生成目录不能为空")
	}
	// 要写入的数据
	data := make([][]string, 0)
	for _, value := range fileName {
		tmpData := []string{value}
		data = append(data, tmpData)
	}

	fullPath := filepath.Join(csvPath, "替换模板内容.csv")
	fmt.Println("开始创建文件名目录表格", fullPath)
	fmt.Println("..........")
	fmt.Println(".........")
	fmt.Println("....")
	fmt.Println(".")
	// 创建一个新的CSV文件
	file, err := os.Create(fullPath)
	if err != nil {
		return err
	}
	defer file.Close()

	// 创建一个CSV写入器
	writer := csv.NewWriter(file)
	defer writer.Flush()

	// 将数据写入CSV文件
	for _, row := range data {
		err := writer.Write(row)
		if err != nil {
			return err
		}
	}
	return nil
}

/**
 * @Description:读取指定csv的内容
 * @param csvPath
 * @author liyuan
 */
func readWordCsvFile(csvPath string) ([][]string, error) {
	data := make([][]string, 0)
	fullPath := filepath.Join(csvPath, "替换模板内容.csv")
	// 打开CSV文件
	//file, err := os.Open(fullPath)
	file, err := ioutil.ReadFile(fullPath)
	if err != nil {
		return data, err
	}
	//defer file.Close()

	// 创建一个CSV阅读器
	//reader := csv.NewReader(file)
	reader := csv.NewReader(transform.NewReader(bytes.NewReader(file), simplifiedchinese.GBK.NewDecoder()))
	reader.FieldsPerRecord = -1
	// 读取所有行
	records, err := reader.ReadAll()
	if err != nil {
		return data, err
	}
	data = records
	return data, nil
}

/**
 * @Description: 替换word内容，生成指定的文件
 * @param templateFile
 * @param savePath
 * @param replaceContent
 * @author liyuan
 */
func replaceWordText(templateFile string, savePath string, replaceContent []string, placeNum int) {
	if replaceContent[0] == "" {
		fmt.Println("替换占位符1的数据为空，跳过")
		return
	}
	doc, err := document.Open(templateFile) // 获取模板文档路径
	if err != nil {
		fmt.Println("读取doc模板错误，请检查模板目录是否正确")
	}
	// 获取全部的段落信息
	paragraphs := make([]document.Paragraph, 0)
	for _, p := range doc.Paragraphs() {
		paragraphs = append(paragraphs, p)
	}
	for _, sdt := range doc.StructuredDocumentTags() {
		for _, p := range sdt.Paragraphs() {
			paragraphs = append(paragraphs, p)
		}
	}
	// 遍历文档中的所有表格
	for _, tbl := range doc.Tables() {
		// 遍历表格的所有行
		for _, row := range tbl.Rows() {
			// 遍历行中的所有单元格
			for _, cell := range row.Cells() {
				// 获取单元格中的文本内容
				for _, p := range cell.Paragraphs() {
					paragraphs = append(paragraphs, p)
				}
			}
		}
	}
	// 循环段落并进行文字替换
	for _, p := range paragraphs {

		for _, r := range p.Runs() {
			str := r.Text()
			// 检测str中是否包含"位符"
			replaceStr := ""
			subStrTemp := "占位符%d"
			for i := 0; i < placeNum; i++ {
				subStr := fmt.Sprintf(subStrTemp, (i + 1))
				if strings.Contains(str, subStr) {
					replaceStr = strings.Replace(str, subStr, replaceContent[i], -1)
				} else {
					replaceStr = ""
				}
				if replaceStr != "" {
					r.ClearContent() // 清除原有的文字信息和换行符
					r.AddText(replaceStr)
				}
			}
		}
	}

	saveFileName := fmt.Sprintf("%s-%s.docx", replaceContent[0], replaceContent[1])
	finalPath := filepath.Join(savePath, saveFileName)
	fmt.Println("正在保存文件", finalPath)
	fmt.Println("...")
	saveErr := doc.SaveToFile(finalPath) // 生成替换后的新文档
	if saveErr != nil {
		fmt.Println("创建文件错误", saveErr.Error())
	}
}
